home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Libraries / Apache 1.0 / src / mod_dir.c < prev    next >
Text File  |  1995-12-04  |  25KB  |  830 lines

  1.  
  2. /* ====================================================================
  3.  * Copyright (c) 1995 The Apache Group.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * 1. Redistributions of source code must retain the above copyright
  10.  *    notice, this list of conditions and the following disclaimer. 
  11.  *
  12.  * 2. Redistributions in binary form must reproduce the above copyright
  13.  *    notice, this list of conditions and the following disclaimer in
  14.  *    the documentation and/or other materials provided with the
  15.  *    distribution.
  16.  *
  17.  * 3. All advertising materials mentioning features or use of this
  18.  *    software must display the following acknowledgment:
  19.  *    "This product includes software developed by the Apache Group
  20.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  21.  *
  22.  * 4. The names "Apache Server" and "Apache Group" must not be used to
  23.  *    endorse or promote products derived from this software without
  24.  *    prior written permission.
  25.  *
  26.  * 5. Redistributions of any form whatsoever must retain the following
  27.  *    acknowledgment:
  28.  *    "This product includes software developed by the Apache Group
  29.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  30.  *
  31.  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
  32.  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  33.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  34.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
  35.  * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  36.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  37.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  38.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  39.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  40.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  41.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  42.  * OF THE POSSIBILITY OF SUCH DAMAGE.
  43.  * ====================================================================
  44.  *
  45.  * This software consists of voluntary contributions made by many
  46.  * individuals on behalf of the Apache Group and was originally based
  47.  * on public domain software written at the National Center for
  48.  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
  49.  * For more information on the Apache Group and the Apache HTTP server
  50.  * project, please see <http://www.apache.org/>.
  51.  *
  52.  */
  53.  
  54.  
  55. /*
  56.  * http_dir.c: Handles the on-the-fly html index generation
  57.  * 
  58.  * Rob McCool
  59.  * 3/23/93
  60.  * 
  61.  * Adapted to Shambhala by rst.
  62.  */
  63.  
  64. #include "httpd.h"
  65. #include "http_config.h"
  66. #include "http_core.h"
  67. #include "http_request.h"
  68. #include "http_protocol.h"
  69. #include "http_log.h"
  70. #include "http_main.h"
  71. #include "util_script.h"
  72.  
  73. module dir_module;
  74.  
  75. /****************************************************************
  76.  *
  77.  * Handling configuration directives...
  78.  */
  79.  
  80. #define FANCY_INDEXING 1    /* Indexing options */
  81. #define ICONS_ARE_LINKS 2
  82. #define SCAN_HTML_TITLES 4
  83. #define SUPPRESS_LAST_MOD 8
  84. #define SUPPRESS_SIZE 16
  85. #define SUPPRESS_DESC 32
  86.  
  87. struct item {
  88.     char *type;
  89.     char *apply_to;
  90.     char *apply_path;
  91.     char *data;
  92. };
  93.  
  94. typedef struct dir_config_struct {
  95.  
  96.     char *default_icon;
  97.     char *index_names;
  98.   
  99.     array_header *icon_list, *alt_list, *desc_list, *ign_list;
  100.     array_header *hdr_list, *rdme_list, *opts_list;
  101.   
  102. } dir_config_rec;
  103.  
  104. char c_by_encoding, c_by_type, c_by_path;
  105.  
  106. #define BY_ENCODING &c_by_encoding
  107. #define BY_TYPE &c_by_type
  108. #define BY_PATH &c_by_path
  109.  
  110. void push_item(array_header *arr, char *type, char *to, char *path, char *data)
  111. {
  112.     struct item *p = (struct item *)push_array(arr);
  113.  
  114.     if (!to) to = "";
  115.     if (!path) path = "";
  116.     
  117.     p->type = type;
  118.     p->data = data ? pstrdup(arr->pool, data): NULL;
  119.     p->apply_path = pstrcat(arr->pool, path, "*", NULL);
  120.     
  121.     if((type == BY_PATH) && (!is_matchexp(to)))
  122.         p->apply_to = pstrcat (arr->pool, "*", to, NULL);
  123.     else if (to)
  124.         p->apply_to = pstrdup (arr->pool, to);
  125.     else
  126.         p->apply_to = NULL;
  127. }
  128.  
  129. char *add_alt(cmd_parms *cmd, void *d, char *alt, char *to)
  130. {
  131.     if (cmd->info == BY_PATH)
  132.         if(!strcmp(to,"**DIRECTORY**"))
  133.             to = "^^DIRECTORY^^";
  134.  
  135.     push_item(((dir_config_rec *)d)->alt_list, cmd->info, to, cmd->path, alt);
  136.     return NULL;
  137. }
  138.  
  139. char *add_icon(cmd_parms *cmd, void *d, char *icon, char *to)
  140. {
  141.     char *iconbak = pstrdup (cmd->pool, icon);
  142.  
  143.     if(icon[0] == '(') {
  144.         char *alt = getword (cmd->pool, &iconbak, ',');
  145.         iconbak[strlen(iconbak) - 1] = '\0'; /* Lose closing paren */
  146.         add_alt(cmd, d, &alt[1], to);
  147.     }
  148.     if(cmd->info == BY_PATH) 
  149.         if(!strcmp(to,"**DIRECTORY**"))
  150.             to = "^^DIRECTORY^^";
  151.  
  152.     push_item(((dir_config_rec *)d)->icon_list, cmd->info, to, cmd->path,
  153.           iconbak);
  154.     return NULL;
  155. }
  156.  
  157. char *add_desc(cmd_parms *cmd, void *d, char *desc, char *to)
  158. {
  159.     push_item(((dir_config_rec *)d)->desc_list, cmd->info, to, cmd->path,desc);
  160.     return NULL;
  161. }
  162.  
  163. char *add_ignore(cmd_parms *cmd, void *d, char *ext) {
  164.     push_item(((dir_config_rec *)d)->ign_list, 0, ext, cmd->path, NULL);
  165.     return NULL;
  166. }
  167.  
  168. char *add_header(cmd_parms *cmd, void *d, char *name) {
  169.     push_item(((dir_config_rec *)d)->hdr_list, 0, NULL, cmd->path, name);
  170.     return NULL;
  171. }
  172.  
  173. char *add_readme(cmd_parms *cmd, void *d, char *name) {
  174.     push_item(((dir_config_rec *)d)->rdme_list, 0, NULL, cmd->path, name);
  175.     return NULL;
  176. }
  177.  
  178.  
  179. char *add_opts_int(cmd_parms *cmd, void *d, int opts) {
  180.     push_item(((dir_config_rec *)d)->opts_list, (char*)opts, NULL,
  181.           cmd->path, NULL);
  182.     return NULL;
  183. }
  184.  
  185. char *fancy_indexing (cmd_parms *cmd, void *d, int arg)
  186. {
  187.     return add_opts_int (cmd, d, arg? FANCY_INDEXING : 0);
  188. }
  189.  
  190. char *add_opts(cmd_parms *cmd, void *d, char *optstr) {
  191.     char *w;
  192.     int opts = 0;
  193.  
  194.     while(optstr[0]) {
  195.         w = getword_conf(cmd->pool, &optstr);
  196.         if(!strcasecmp(w,"FancyIndexing"))
  197.             opts |= FANCY_INDEXING;
  198.         else if(!strcasecmp(w,"IconsAreLinks"))
  199.             opts |= ICONS_ARE_LINKS;
  200.         else if(!strcasecmp(w,"ScanHTMLTitles"))
  201.             opts |= SCAN_HTML_TITLES;
  202.         else if(!strcasecmp(w,"SuppressLastModified"))
  203.             opts |= SUPPRESS_LAST_MOD;
  204.         else if(!strcasecmp(w,"SuppressSize"))
  205.             opts |= SUPPRESS_SIZE;
  206.         else if(!strcasecmp(w,"SuppressDescription"))
  207.             opts |= SUPPRESS_DESC;
  208.         else if(!strcasecmp(w,"None"))
  209.             opts = 0;
  210.     else
  211.         return "Invalid directory indexing option";
  212.     }
  213.     return add_opts_int(cmd, d, opts);
  214. }
  215.  
  216. #define DIR_CMD_PERMS OR_INDEXES
  217.  
  218. command_rec dir_cmds[] = {
  219. { "AddIcon", add_icon, BY_PATH, DIR_CMD_PERMS, ITERATE2,
  220.     "an icon URL followed by one or more filenames" },
  221. { "AddIconByType", add_icon, BY_TYPE, DIR_CMD_PERMS, ITERATE2,
  222.     "an icon URL followed by one or more MIME types" },
  223. { "AddIconByEncoding", add_icon, BY_ENCODING, DIR_CMD_PERMS, ITERATE2,
  224.     "an icon URL followed by one or more content encodings" },
  225. { "AddAlt", add_alt, BY_PATH, DIR_CMD_PERMS, ITERATE2,
  226.     "alternate descriptive text followed by one or more filenames" },
  227. { "AddAltByType", add_alt, BY_TYPE, DIR_CMD_PERMS, ITERATE2,
  228.     "alternate descriptive text followed by one or more MIME types" },
  229. { "AddAltByEncoding", add_alt, BY_ENCODING, DIR_CMD_PERMS, ITERATE2,
  230.     "alternate descriptive text followed by one or more content encodings" },
  231. { "IndexOptions", add_opts, NULL, DIR_CMD_PERMS, RAW_ARGS,
  232.     "one or more index options" },
  233. { "IndexIgnore", add_ignore, NULL, DIR_CMD_PERMS, ITERATE,
  234.     "one or more file extensions" },
  235. { "AddDescription", add_desc, BY_PATH, DIR_CMD_PERMS, ITERATE2,
  236.     "Descriptive text followed by one or more filenames" },
  237. { "HeaderName", add_header, NULL, DIR_CMD_PERMS, TAKE1, "a filename" },
  238. { "ReadmeName", add_readme, NULL, DIR_CMD_PERMS, TAKE1, "a filename" },
  239. { "FancyIndexing", fancy_indexing, NULL, DIR_CMD_PERMS, FLAG, NULL },
  240. { "DefaultIcon", set_string_slot,
  241.     (void*)XtOffsetOf(dir_config_rec, default_icon),
  242.     DIR_CMD_PERMS, TAKE1, "an icon URL"},
  243. { "DirectoryIndex", set_string_slot,
  244.     (void*)XtOffsetOf(dir_config_rec, index_names),
  245.     DIR_CMD_PERMS, RAW_ARGS, NULL },
  246. { NULL }
  247. };
  248.  
  249. void *create_dir_config (pool *p, char *dummy)
  250. {
  251.     dir_config_rec *new =
  252.         (dir_config_rec *) pcalloc (p, sizeof(dir_config_rec));
  253.  
  254.     new->index_names = NULL;
  255.     new->icon_list = make_array (p, 4, sizeof (struct item));
  256.     new->alt_list = make_array (p, 4, sizeof (struct item));
  257.     new->desc_list = make_array (p, 4, sizeof (struct item));
  258.     new->ign_list = make_array (p, 4, sizeof (struct item));
  259.     new->hdr_list = make_array (p, 4, sizeof (struct item));
  260.     new->rdme_list = make_array (p, 4, sizeof (struct item));
  261.     new->opts_list = make_array (p, 4, sizeof (struct item));
  262.     
  263.     return (void *)new;
  264. }
  265.  
  266. void *merge_dir_configs (pool *p, void *basev, void *addv)
  267. {
  268.     dir_config_rec *new=(dir_config_rec*)pcalloc (p, sizeof(dir_config_rec));
  269.     dir_config_rec *base = (dir_config_rec *)basev;
  270.     dir_config_rec *add = (dir_config_rec *)addv;
  271.  
  272.     new->default_icon = add->default_icon?add->default_icon:base->default_icon;
  273.     new->index_names = add->index_names? add->index_names: base->index_names;
  274.  
  275.     new->alt_list = append_arrays (p, add->alt_list, base->alt_list);
  276.     new->ign_list = append_arrays (p, add->ign_list, base->ign_list);
  277.     new->hdr_list = append_arrays (p, add->hdr_list, base->hdr_list);
  278.     new->desc_list = append_arrays (p, add->desc_list, base->desc_list);
  279.     new->icon_list = append_arrays (p, add->icon_list, base->icon_list);
  280.     new->rdme_list = append_arrays (p, add->rdme_list, base->rdme_list);
  281.     new->opts_list = append_arrays (p, add->opts_list, base->opts_list);
  282.     
  283.     return new;
  284. }
  285.  
  286. /****************************************************************
  287.  *
  288.  * Looking things up in config entries...
  289.  */
  290.  
  291. /* Structure used to hold entries when we're actually building an index */
  292.  
  293. struct ent {
  294.     char *name;
  295.     char *icon;
  296.     char *alt;
  297.     char *desc;
  298.     size_t size;
  299.     time_t lm;
  300.     struct ent *next;
  301. };
  302.  
  303. char *find_item(request_rec *r, array_header *list, int path_only) {
  304.     char *content_type = r->content_type;
  305.     char *content_encoding = r->content_encoding;
  306.     char *path = r->filename;
  307.  
  308.     struct item *items = (struct item *)list->elts;
  309.     int i;
  310.  
  311.     for (i = 0; i < list->nelts; ++i) {
  312.         struct item *p = &items[i];
  313.       
  314.         /* Special cased for ^^DIRECTORY^^ and ^^BLANKICON^^ */
  315.         if((path[0] == '^') || (!strcmp_match(path,p->apply_path))) {
  316.             if(!*(p->apply_to))
  317.                 return p->data;
  318.             else if(p->type == BY_PATH || path[0] == '^') {
  319.                 if(!strcmp_match(path,p->apply_to))
  320.                     return p->data;
  321.             } else if(!path_only) {
  322.                 if(!content_encoding) {
  323.                     if(p->type == BY_TYPE) {
  324.                         if(!strcmp_match(content_type,p->apply_to))
  325.                             return p->data;
  326.                     }
  327.                 } else {
  328.                     if(p->type == BY_ENCODING) {
  329.                         if(!strcmp_match(content_encoding,p->apply_to))
  330.                             return p->data;
  331.                     }
  332.                 }
  333.             }
  334.         }
  335.     }
  336.     return NULL;
  337. }
  338.  
  339. #define find_icon(d,p,t) find_item(p,d->icon_list,t)
  340. #define find_alt(d,p,t) find_item(p,d->alt_list,t)
  341. #define find_desc(d,p) find_item(p,d->desc_list,0)
  342. #define find_header(d,p) find_item(p,d->hdr_list,0)
  343. #define find_readme(d,p) find_item(p,d->rdme_list,0)
  344.  
  345. char *find_default_icon (dir_config_rec *d, char *bogus_name)
  346. {
  347.     request_rec r;
  348.  
  349.     /* Bleah.  I tried to clean up find_item, and it lead to this bit
  350.      * of ugliness.   Note that the fields initialized are precisely
  351.      * those that find_item looks at...
  352.      */
  353.     
  354.     r.filename = bogus_name;
  355.     r.content_type = r.content_encoding = NULL;
  356.  
  357.     return find_item (&r, d->icon_list, 1);
  358. }
  359.  
  360. int ignore_entry(dir_config_rec *d, char *path) {
  361.     array_header *list = d->ign_list;
  362.     struct item *items = (struct item *)list->elts;
  363.     char *tt;
  364.     int i;
  365.  
  366.     if((tt=strrchr(path,'/')) == NULL)
  367.       tt=path;
  368.     else {
  369.       tt++;
  370.     }
  371.  
  372.     for (i = 0; i < list->nelts; ++i) {
  373.         struct item *p = &items[i];
  374.     char *ap;
  375.  
  376.     if((ap=strrchr(p->apply_to,'/')) == NULL)
  377.       ap=p->apply_to;
  378.     else
  379.       ap++;
  380.  
  381.         if(!strcmp_match(path,p->apply_path) && !strcmp_match(tt,ap))
  382.        return 1;
  383.     }
  384.     return 0;
  385. }
  386.  
  387. int find_opts(dir_config_rec *d, request_rec *r) {
  388.     char *path = r->filename;
  389.     array_header *list = d->opts_list;
  390.     struct item *items = (struct item *)list->elts;
  391.     int i;
  392.  
  393.     for (i = 0; i < list->nelts; ++i) {
  394.         struct item *p = &items[i];
  395.     
  396.         if(!strcmp_match(path,p->apply_path))
  397.             return (int)p->type;
  398.     }
  399.     return 0;
  400. }
  401.  
  402. /*****************************************************************
  403.  *
  404.  * Actually generating output
  405.  */
  406.  
  407.  
  408. int insert_readme(char *name, char *readme_fname, int rule, request_rec *r) {
  409.     char *fn;
  410.     FILE *f;
  411.     struct stat finfo;
  412.     int plaintext=0;
  413.  
  414.     fn = make_full_path(r->pool, name, readme_fname);
  415.     fn = pstrcat(r->pool, fn, ".html", NULL);
  416.     if(stat(fn,&finfo) == -1) {
  417.         /* A brief fake multiviews search for README.html */
  418.         fn[strlen(fn)-5] = '\0';
  419.         if(stat(fn,&finfo) == -1)
  420.             return 0;
  421.         plaintext=1;
  422.         if(rule) rprintf(r,"<HR>%c",LF);
  423.         rprintf(r,"<PRE>%c",LF);
  424.     }
  425.     else if(rule) rprintf(r,"<HR>%c",LF);
  426.     if(!(f = pfopen(r->pool,fn,"r")))
  427.         return 0;
  428.     send_fd(f, r);
  429.     pfclose(r->pool, f);
  430.     if(plaintext)
  431.         rprintf(r,"</PRE>%c",LF);
  432.     return 1;
  433. }
  434.  
  435.  
  436. char *find_title(request_rec *r) {
  437.     char titlebuf[MAX_STRING_LEN], *find = "<TITLE>";
  438.     FILE *thefile = NULL;
  439.     int x,y,n,p;
  440.  
  441.     if ((!strcmp(r->content_type,"text/html")) && (!r->content_encoding)) {
  442.         if(!(thefile = pfopen(r->pool, r->filename,"r")))
  443.             return NULL;
  444.         n = fread(titlebuf,sizeof(char),MAX_STRING_LEN - 1,thefile);
  445.         titlebuf[n] = '\0';
  446.         for(x=0,p=0;titlebuf[x];x++) {
  447.             if(titlebuf[x] == find[p]) {
  448.                 if(!find[++p]) {
  449.                     if((p = ind(&titlebuf[++x],'<')) != -1)
  450.                         titlebuf[x+p] = '\0';
  451.                     /* Scan for line breaks for Tanmoy's secretary */
  452.                     for(y=x;titlebuf[y];y++)
  453.                         if((titlebuf[y] == CR) || (titlebuf[y] == LF))
  454.                             titlebuf[y] = ' ';
  455.             pfclose (r->pool, thefile);
  456.                     return pstrdup(r->pool, &titlebuf[x]);
  457.                 }
  458.             } else p=0;
  459.         }
  460.     pfclose(r->pool, thefile);
  461.     }
  462.     return NULL;
  463. }
  464.  
  465.  
  466. #ifdef NOTDEF
  467.  
  468. /* The only call to this function anyplace is commented out in the base
  469.  * code below.  It could be fixed along the same lines as the shell_escape
  470.  * stuff in util.c, but for now, why bother?
  471.  */
  472.  
  473. void escape_html(char *fn) {
  474.     register int x,y;
  475.     char copy[MAX_STRING_LEN];
  476.  
  477.     strcpy(copy,fn);
  478.     for(x=0,y=0;copy[y];x++,y++) {
  479.         if(copy[y] == '<') {
  480.             strcpy(&fn[x],"<");
  481.             x+=3;
  482.         }
  483.         else if(copy[y] == '>') {
  484.             strcpy(&fn[x],">");
  485.             x+=3;
  486.         }
  487.         else if(copy[y] == '&') {
  488.             strcpy(&fn[x],"&");
  489.             x+=4;
  490.         }
  491.         else
  492.             fn[x] = copy[y];
  493.     }
  494.     fn[x] = '\0';
  495. }
  496. #endif
  497.  
  498. struct ent *make_dir_entry(char *name, int dir_opts,
  499.                dir_config_rec *d, request_rec *r)
  500. {
  501.     struct ent *p;
  502.  
  503.     if((name[0] == '.') && (!name[1]))
  504.         return(NULL);
  505.  
  506.     if (ignore_entry(d, make_full_path (r->pool, r->filename, name)))
  507.         return(NULL);
  508.  
  509.     p=(struct ent *)pcalloc(r->pool, sizeof(struct ent));
  510.     p->name = pstrdup (r->pool, name);
  511.     p->size = -1;
  512.     p->icon = NULL;
  513.     p->alt = NULL;
  514.     p->desc = NULL;
  515.     p->lm = -1;
  516.  
  517.     if(dir_opts & FANCY_INDEXING) {
  518.         request_rec *rr = sub_req_lookup_file (name, r);
  519.     
  520.     if (rr->finfo.st_mode != 0) {
  521.             p->lm = rr->finfo.st_mtime;
  522.             if(S_ISDIR(rr->finfo.st_mode)) {
  523.                 if(!(p->icon = find_icon(d,rr,1)))
  524.                     p->icon = find_default_icon(d,"^^DIRECTORY^^");
  525.                 if(!(p->alt = find_alt(d,rr,1)))
  526.                     p->alt = "DIR";
  527.                 p->size = -1;
  528.         p->name = pstrcat (r->pool, name, "/", NULL);
  529.             }
  530.             else {
  531.                 p->icon = find_icon(d, rr, 0);
  532.                 p->alt = find_alt(d, rr, 0);
  533.                 p->size = rr->finfo.st_size;
  534.             }
  535.         }
  536.     
  537.         p->desc = find_desc(d, rr);
  538.     
  539.         if((!p->desc) && (dir_opts & SCAN_HTML_TITLES))
  540.             p->desc = pstrdup (r->pool, find_title(rr));
  541.  
  542.     destroy_sub_req (rr);
  543.     }
  544.     return(p);
  545. }
  546.  
  547. char *terminate_description(dir_config_rec *d, char *desc, int dir_opts) {
  548.     int maxsize = 23;
  549.     register int x;
  550.     
  551.     if(dir_opts & SUPPRESS_LAST_MOD) maxsize += 17;
  552.     if(dir_opts & SUPPRESS_SIZE) maxsize += 7;
  553.  
  554.     for(x=0;desc[x] && maxsize;x++) {
  555.         if(desc[x] == '<') {
  556.             while(desc[x] != '>') {
  557.                 if(!desc[x]) {
  558.                     maxsize = 0;
  559.                     break;
  560.                 }
  561.                 ++x;
  562.             }
  563.         }
  564.         else --maxsize;
  565.     }
  566.     if(!maxsize) {
  567.         desc[x-1] = '>';    /* Grump. */
  568.     desc[x] = '\0';        /* Double Grump! */
  569.     }
  570.     return desc;
  571. }
  572.  
  573. void output_directories(struct ent **ar, int n,
  574.             dir_config_rec *d, request_rec *r, int dir_opts)
  575. {
  576.     int x;
  577.     char *name = r->uri;
  578.     char *tp;
  579.     pool *scratch = make_sub_pool (r->pool);
  580.     
  581.     if(name[0] == '\0') name = "/";
  582.  
  583.     if(dir_opts & FANCY_INDEXING) {
  584.         rprintf (r, "<PRE>");
  585.         if((tp = find_default_icon(d,"^^BLANKICON^^")))
  586.             rprintf(r, "<IMG SRC=\"%s\" ALT=\"     \"> ", tp);
  587.         rprintf (r, "Name                   ");
  588.         if(!(dir_opts & SUPPRESS_LAST_MOD))
  589.             rprintf(r, "Last modified     ");
  590.         if(!(dir_opts & SUPPRESS_SIZE))
  591.             rprintf(r, "Size  ");
  592.         if(!(dir_opts & SUPPRESS_DESC))
  593.             rprintf(r, "Description");
  594.         rprintf(r,"%c<HR>%c",LF,LF);
  595.     }
  596.     else {
  597.         rprintf (r, "<UL>");
  598.     }
  599.         
  600.     for(x=0;x<n;x++) {
  601.     char *anchor = NULL, *t = NULL, *t2 = NULL;
  602.     
  603.     clear_pool (scratch);
  604.     
  605.         if((!strcmp(ar[x]->name,"../")) || (!strcmp(ar[x]->name,".."))) {
  606.             char *t = make_full_path (scratch, name, "../");
  607.             getparents(t);
  608.             if(t[0] == '\0') t = "/";
  609.         anchor = pstrcat (scratch, "<A HREF=\"", os_escape_path(scratch, t),
  610.                   "\">", NULL);
  611.         t2 = "Parent Directory</A>";
  612.         }
  613.         else {
  614.         t = ar[x]->name;
  615.         t2 = pstrdup(scratch, t);
  616.             if(strlen(t2) > 21) {
  617.                 t2[21] = '\0';
  618.         t2 = pstrcat (scratch, t2, "</A>..", NULL);
  619.             } else 
  620.             /* screws up formatting, but some need it. should fix. */
  621.         /* escape_html(t2); */
  622.             t2 = pstrcat(scratch, t2, "</A>", NULL);
  623.         anchor = pstrcat (scratch, "<A HREF=\"", os_escape_path(scratch, t),
  624.                   "\">", NULL);
  625.         }
  626.  
  627.         if(dir_opts & FANCY_INDEXING) {
  628.             if(dir_opts & ICONS_ARE_LINKS)
  629.                 rprintf (r,"%s",anchor);
  630.             if((ar[x]->icon) || d->default_icon) {
  631.                 rprintf(r, "<IMG SRC=\"%s\" ALT=\"[%s]\">",
  632.             ar[x]->icon ? ar[x]->icon : d->default_icon,
  633.             ar[x]->alt ? ar[x]->alt : "   ");
  634.             }
  635.             if(dir_opts & ICONS_ARE_LINKS) 
  636.                 rprintf (r, "</A>");
  637.  
  638.             rprintf(r," %s%-27.29s", anchor, t2);
  639.             if(!(dir_opts & SUPPRESS_LAST_MOD)) {
  640.                 if(ar[x]->lm != -1) {
  641.             char time[MAX_STRING_LEN];
  642.                     struct tm *ts = localtime(&ar[x]->lm);
  643.                     strftime(time,MAX_STRING_LEN,"%d-%b-%y %H:%M  ",ts);
  644.             rprintf (r, "%s", time);
  645.                 }
  646.                 else {
  647.                     rprintf(r, "                 ");
  648.                 }
  649.             }
  650.             if(!(dir_opts & SUPPRESS_SIZE)) {
  651.                 send_size(ar[x]->size,r);
  652.                 rprintf (r, "  ");
  653.             }
  654.             if(!(dir_opts & SUPPRESS_DESC)) {
  655.                 if(ar[x]->desc) {
  656.                     rprintf(r,"%s",
  657.                 terminate_description(d, ar[x]->desc, dir_opts));
  658.                 }
  659.             }
  660.         }
  661.         else
  662.             rprintf(r, "<LI> %s %s",anchor,t2);
  663.         rputc(LF,r);
  664.     }
  665.     if(dir_opts & FANCY_INDEXING) {
  666.         rprintf(r, "</PRE>");
  667.     }
  668.     else {
  669.         rprintf(r, "</UL>");
  670.     }
  671. }
  672.  
  673.  
  674. int dsortf(struct ent **s1,struct ent **s2)
  675. {
  676.     return(strcmp((*s1)->name,(*s2)->name));
  677. }
  678.  
  679.     
  680. int index_directory(request_rec *r, dir_config_rec *dir_conf)
  681. {
  682.     char *title_name = pstrdup (r->pool, r->uri);
  683.     char *title_endp;
  684.     char *name = r->filename;
  685.     
  686.     DIR *d;
  687.     struct DIR_TYPE *dstruct;
  688.     int num_ent=0,x;
  689.     struct ent *head,*p;
  690.     struct ent **ar;
  691.     char *tmp;
  692.     int dir_opts = find_opts(dir_conf, r);
  693.  
  694.     if(!(d=opendir(name))) return FORBIDDEN;
  695.  
  696.     r->content_type = "text/html";
  697.     
  698.     soft_timeout ("send directory", r);
  699.     send_http_header(r);
  700.  
  701.     if (r->header_only) {
  702.     closedir (d);
  703.     return 0;
  704.     }
  705.  
  706.     /* Spew HTML preamble */
  707.     
  708.     title_endp = title_name + strlen(title_name) - 1;
  709.  
  710.     while (title_endp > title_name && *title_endp == '/')
  711.     *title_endp-- = '\0';
  712.     
  713.     rprintf (r,"<HEAD><TITLE>Index of %s</TITLE></HEAD><BODY>%c",
  714.          title_name, LF);
  715.  
  716.     if((!(tmp = find_header(dir_conf,r))) || (!(insert_readme(name,tmp,0,r))))
  717.         rprintf(r,"<H1>Index of %s</H1>%c",title_name,LF);
  718.  
  719.     /* 
  720.      * Since we don't know how many dir. entries there are, put them into a 
  721.      * linked list and then arrayificate them so qsort can use them. 
  722.      */
  723.     head=NULL;
  724.     while((dstruct=readdir(d))) {
  725.         if((p = make_dir_entry(dstruct->d_name, dir_opts, dir_conf, r))) {
  726.             p->next=head;
  727.             head=p;
  728.             num_ent++;
  729.         }
  730.     }
  731.     ar=(struct ent **) palloc(r->pool, num_ent*sizeof(struct ent *));
  732.     p=head;
  733.     x=0;
  734.     while(p) {
  735.         ar[x++]=p;
  736.         p = p->next;
  737.     }
  738.     
  739.     qsort((void *)ar,num_ent,sizeof(struct ent *),
  740. #ifdef ULTRIX_BRAIN_DEATH
  741.           (int (*))dsortf);
  742. #else
  743.           (int (*)(const void *,const void *))dsortf);
  744. #endif
  745.      output_directories(ar, num_ent, dir_conf, r, dir_opts);
  746.      closedir(d);
  747.  
  748.      if (dir_opts & FANCY_INDEXING)
  749.          if((tmp = find_readme(dir_conf, r)))
  750.              insert_readme(name,tmp,1,r);
  751.      else {
  752.          rprintf(r, "</UL>");
  753.      }
  754.  
  755.      rprintf(r, "</BODY>");
  756.      return 0;
  757. }
  758.  
  759. /* The formal handler... */
  760.  
  761. int handle_dir (request_rec *r)
  762. {
  763.     dir_config_rec *d =
  764.       (dir_config_rec *)get_module_config (r->per_dir_config, &dir_module);
  765.     char *names_ptr = d->index_names ? d->index_names : DEFAULT_INDEX;
  766.     int allow_opts = allow_options (r);
  767.  
  768.     if (r->method_number != M_GET) return NOT_IMPLEMENTED;
  769.     
  770.     if (r->uri[0] == '\0' || r->uri[strlen(r->uri)-1] != '/') {
  771.         char* ifile = pstrcat (r->pool, r->uri, "/", NULL);
  772.     table_set (r->headers_out, "Location",
  773.            construct_url(r->pool, ifile, r->server));
  774.     return REDIRECT;
  775.     }
  776.  
  777.     /* KLUDGE --- make the sub_req lookups happen in the right directory.
  778.      * Fixing this in the sub_req_lookup functions themselves is difficult,
  779.      * and would probably break virtual includes...
  780.      */
  781.  
  782.     r->filename = pstrcat (r->pool, r->filename, "/", NULL);
  783.     
  784.     while (*names_ptr) {
  785.           
  786.     char *name_ptr = getword_conf (r->pool, &names_ptr);
  787.     request_rec *rr = sub_req_lookup_uri (name_ptr, r);
  788.            
  789.     if (rr->status == 200 && rr->finfo.st_mode != 0) {
  790.             char *new_uri = escape_uri(r->pool, rr->uri);
  791.         destroy_sub_req (rr);
  792.         internal_redirect (new_uri, r);
  793.         return OK;
  794.     }
  795.  
  796.         destroy_sub_req (rr);
  797.     }
  798.  
  799.     /* OK, nothing easy.  Trot out the heavy artillery... */
  800.  
  801.     if (allow_opts & OPT_INDEXES) 
  802.         return index_directory (r, d);
  803.     else
  804.         return FORBIDDEN;
  805. }
  806.  
  807.  
  808. handler_rec dir_handlers[] = {
  809. { DIR_MAGIC_TYPE, handle_dir },
  810. { NULL }
  811. };
  812.  
  813. module dir_module = {
  814.    STANDARD_MODULE_STUFF,
  815.    NULL,            /* initializer */
  816.    create_dir_config,        /* dir config creater */
  817.    merge_dir_configs,        /* dir merger --- default is to override */
  818.    NULL,            /* server config */
  819.    NULL,            /* merge server config */
  820.    dir_cmds,            /* command table */
  821.    dir_handlers,        /* handlers */
  822.    NULL,            /* filename translation */
  823.    NULL,            /* check_user_id */
  824.    NULL,            /* check auth */
  825.    NULL,            /* check access */
  826.    NULL,            /* type_checker */
  827.    NULL,            /* fixups */
  828.    NULL                /* logger */
  829. };
  830.